import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Map;
import java.util.TreeMap;
import java.util.regex.*;
/*
* Класс-фабрика объектов FileCSV.
* Принимает, проверяет и рекурсивно просматривает директории и файлы
* Залезает во все нескрытые поддиректории, куда дадут залезть
* Выбрасывает IOException, если первично заданный файл не может быть открыт
* В остальных случаях возвращает либо список объектов, либо null
*/
public class FactoryCSV {
    //Карта шаблонов для Tuple
    private final static TreeMap<String, String[]> tupleTypes =
            new TreeMap<>(Map.ofEntries(
                    Map.entry("m", new String[]{"String", "Boolean", "Integer", "Integer"}),
                    Map.entry("y", new String[]{"Integer", "Integer", "Boolean"})
    ));
    private static String[] getType(String key) throws IOException {
        if (!tupleTypes.containsKey(key)) {
            throw (new IOException("Invalid file type"));
        }
        return tupleTypes.get(key);
    }
    private static void checkExistance(Path path) throws IOException {
        if (!Files.exists(path)) {
            throw (new IOException("File doesn't exist"));
        }
    }
    private static void checkReadable(Path path) throws IOException {
        if (!Files.isReadable(path)) {
            throw (new IOException("File cannot be read"));
        }
    }
    //Проверяет директорию, конструирует и возвращает все FileCSV
    private static ArrayList<FileCSV> analyzeDirectory(String pwd, String template) throws IOException {
        Pattern regex = Pattern.compile(template);
        String[] templateCSV = getType(template.substring(0,1));
        ArrayList<FileCSV> ret = new ArrayList<>();
        File dir = new File(pwd);
        ArrayList<String> pathes = recursiveAnalyzeDir(dir, regex);
        if (pathes == null) return null;
        for (String path : pathes) {
            ret.add(new FileCSV(path, templateCSV));
        }
        return ret;
    }
    //Рекурсивная часть вышестоящего метода. Проверка директории, подстановка
    // регулярных выражений и возвращение путей до всех подходящих файлов.
    private static ArrayList<String> recursiveAnalyzeDir(File dir, Pattern regex) {
        ArrayList<String> ret = new ArrayList<>();
        File[] dirFiles = dir.listFiles();
        if (dirFiles == null) return null;
        for (File file : dirFiles) {
            if(!file.canRead()||file.isHidden()) continue;
            if(file.isDirectory()) {
                ret.addAll(recursiveAnalyzeDir(file,regex));
                continue;
            }
            if (regex.matcher(file.getName()).matches()) {
                ret.add(file.getAbsolutePath());
            }
        }
        return ret;
    }

    public static ArrayList<FileCSV> getFiles(String filePath, String template) throws IOException {
        Path path = Path.of(filePath);
        ArrayList<FileCSV> ret = new ArrayList<>();
        checkExistance(path);
        checkReadable(path);
        if (Files.isDirectory(path)) {
            return analyzeDirectory(filePath, template);
        }
        //С симлинками не работаем.
        if (Files.isRegularFile(path)) {
            ret.add(new FileCSV(filePath, getType(template.substring(0, 1))));
            return ret;
        }
        return null;
    }
}
